﻿using System;
using System.Collections.Generic;
using System.Linq;

using NHibernate;
using NHibernate.Linq;

using DflyingForum.Core.Data.NHHelper;

namespace DflyingForum.Core.Repositories
{
    public abstract class NHibernateRepository<TEntity, TKey> : IRepository<TEntity, TKey> where TEntity : class
    {

        #region IRepository<TEntity,TKey> 成员

        public virtual TKey Save(TEntity entity)
        {
            return _trans.InsertTransaction(entity);
        }

        public virtual void Update(TEntity entity)
        {
            _trans.UpdateTransaction(entity);
        }

        public virtual void Delete(TEntity entity)
        {
            _trans.DeleteTransaction(entity);
        }

        public TEntity FindBy(TKey id)
        {
            return _session.Get<TEntity>(id);
        }

        /// <summary>
        /// 获取唯一对象,除非能保证获取的对象唯一，否则不要使用
        /// </summary>
        /// <param name="userName"></param>
        /// <returns></returns>
        public TEntity FindBy(string propertyName, object value)
        {
            return _session.CreateCriteria<TEntity>()
                 .Add(NHibernate.Criterion.Expression.Eq(propertyName, value))
                 .UniqueResult<TEntity>();
        }

        public IList<TEntity> FindBy(IList<CriteriaParameter> query)
        {
            var criteria = _session.CreateCriteria<TEntity>();
            criteria = InitCriteria(criteria, query);
            return criteria.List<TEntity>();
        }

        public IList<TEntity> FindBy(Func<TEntity, bool> expression)
        {
            return _session.Query<TEntity>().Where(expression).ToList();
        }

        /// <summary>
        /// 获取分页记录
        /// </summary>
        public IList<TEntity> FindByPage(int currentPage, int pageSize, out int recordCount, IList<CriteriaParameter> query)
        {
            var criteria = _session.CreateCriteria<TEntity>();
            criteria = InitCriteria(criteria, query);//这里query中不能含order by,因为要获取总数，所以要清除排序order

            //利用投影得到总记录数
            var criteriaCount = CriteriaTransformer.Clone(criteria);//克隆是为了不干扰本身的criteria不被干扰
            criteriaCount.ClearOrders();//清除Order
            recordCount = criteriaCount.SetProjection(NHibernate.Criterion.Projections.RowCount()).UniqueResult<int>();

            return criteria.SetFirstResult((currentPage - 1) * pageSize)//考察
                    .SetMaxResults(pageSize)
                    .List<TEntity>();
        }

        /// <summary>
        ///  传入Lamda表达式返回分页数据
        /// </summary>
        public IList<TEntity> FindByPage(int currentPage, int pageSize, out int recordCount, Func<TEntity, bool> expression)
        {
            //获得记录总数,不知道Linq这个记录总数的效率怎么样,带考察
            recordCount = _session.Query<TEntity>().Count(expression);
            return _session.Query<TEntity>().Where(expression).Skip((currentPage - 1) * pageSize).Take(pageSize).ToList();
        }

        public IList<TEntity> FindBy(string hql, string key, object value)
        {
            return FindBy(hql, new string[] { key }, new object[] { value });
        }

        public IList<object[]> FindObjectBy(string hql, string key, object value)
        {
            return FindObjectBy(hql, new string[] { key }, new object[] { value });
        }

        /// <summary>
        /// 根据HQL查询，返回List<T>
        /// </summary>
        public IList<TEntity> FindBy(string hql, string[] keys, object[] values)
        {
            IQuery query = _session.CreateQuery(hql);

            for (int i = 0; i < keys.Length; i++)
            {
                query.SetParameter(keys[i], values[i]);
            }
            return query.List<TEntity>();
        }

        /// <summary>
        /// 根据HQL查询，返回List<object[]>
        /// </summary>
        public IList<object[]> FindObjectBy(string hql, string[] keys, object[] values)
        {
            IQuery query = _session.CreateQuery(hql);

            for (int i = 0; i < keys.Length; i++)
            {
                query.SetParameter(keys[i], values[i]);
            }
            return query.List<object[]>();
        }

        #endregion

        #region 记录总数

        public int GetCount()
        {
            return GetCount(new List<CriteriaParameter>());
        }

        public int GetCount(List<CriteriaParameter> query)
        {
            var criteria = _session.CreateCriteria<TEntity>();
            criteria = InitCriteria(criteria, query);

            //利用投影得到总记录数
            var criteriaCount = CriteriaTransformer.Clone(criteria);//克隆是为了不干扰本身的criteria不被干扰
            criteriaCount.ClearOrders();
            return criteriaCount.SetProjection(NHibernate.Criterion.Projections.RowCount()).UniqueResult<int>();
        }

        #endregion

        #region 私有成员

        private NHTransactionHelper<TEntity, TKey> _trans = new NHTransactionHelper<TEntity, TKey>();

        /// <summary>
        /// 初始化ICriteria对象
        /// </summary>
        private ICriteria InitCriteria(ICriteria criteria, IList<CriteriaParameter> query)
        {
            return CriteriaHelper<TEntity>.InitCriteria(criteria, query);
        }

        #endregion

        #region protected member

        protected ISession _session = SessionManager.GetCurrentSession();

        #endregion
    }
}